/*这是一个字符串格式化，父类和子类的定义*/
#pragma once
#include "loglevel.hpp"
#include <memory>
#include <ostream>
#include "util.hpp"
#include "logmessage.hpp"
#include <ctime>
#include <vector>
#include <assert.h>
#include <sstream>
using std::cerr;
using std::endl;
using std::ostream;
using std::shared_ptr;
using std::string;

namespace mylog
{
    /*格式化父类*/
    class FormatItem
    {
    public:
        using ptr = std::shared_ptr<FormatItem>;
        virtual void Fromat(ostream &out, const LogMsg &msg) = 0;
        FormatItem() {}
    };

    class MsgFormatItem : public FormatItem // 信息格式化子类派生
    {
    public:
        void Fromat(ostream &out, const LogMsg &msg)
        {
            out << msg._message;
        }
    };

    class LevelFormatItem : public FormatItem // 日志等级格式化子类派生
    {
    public:
        void Fromat(ostream &out, const LogMsg &msg)
        {
            out << LogLevel::ToString(msg._level);
        }
    };

    class NameFormatItem : public FormatItem // 日志名称格式化子类派生
    {
    public:
        void Fromat(ostream &out, const LogMsg &msg)
        {
            out << msg._name;
        }
    };

    class FileFormatItem : public FormatItem // 当前文件名格式化子类派生
    {
    public:
        void Fromat(ostream &out, const LogMsg &msg)
        {
            out << msg._file;
        }
    };

    class LineFormatItem : public FormatItem // 代码行号格式化子类派生
    {
    public:
        void Fromat(ostream &out, const LogMsg &msg)
        {
            out << msg._line;
        }
    };

    class TidFormatItem : public FormatItem // 线程ID格式化子类派生
    {
    public:
        void Fromat(ostream &out, const LogMsg &msg)
        {
            out << msg._tid;
        }
    };

    class TimeFormatItem : public FormatItem // 当前时间格式化子类派生
    {
    private:
        const string _format;

    public:
        TimeFormatItem(const string &format = "%H:%M:%S") : _format(format)
        {
        }
        void Fromat(ostream &out, const LogMsg &msg)
        {
            struct tm t;
            localtime_r(&msg._time, &t);
            char time[32];
            strftime(time, sizeof(time) - 1, _format.c_str(), &t);
            out << time;
        }
    };

    class TabFormatItem : public FormatItem // 制表符格式化子类派生
    {
    public:
        void Fromat(ostream &out, const LogMsg &msg)
        {
            out << "\t";
        }
    };

    class NlineFormatItem : public FormatItem // 回车符格式化子类派生
    {
    public:
        void Fromat(ostream &out, const LogMsg &msg)
        {
            out << "\n";
        }
    };

    class OtherFormatItem : public FormatItem // 其他信息格式化子类派生
    {
    private:
        string _msg;

    public:
        OtherFormatItem(const string &msg = "") : _msg(msg) {}
        void Fromat(ostream &out, const LogMsg &msg)
        {
            out << _msg;
        }
    };

    class Formater
    {
    public:
        using ptr = shared_ptr<Formater>;
        Formater(const std::string &pattern = "[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n") : _pattern(pattern)
        {
            assert(parsePattern());
        }
        // 对msg进行格式化
        ostream &format(ostream &out, LogMsg &msg)
        {
            for (auto &it : _items)
            {
                it->Fromat(out, msg);
            }
            return out;
        }
        string format(LogMsg &msg)
        {
            std::stringstream ss;
            for (auto &it : _items)
            {
                it->Fromat(ss, msg);
            }
            return ss.str();
        }
        // 对格式化规则字符串进行解析
        bool parsePattern()
        {
            std::vector<std::tuple<string, string, int>> arry;
            string format_key;
            string format_value;
            string string_value;
            bool sub_false = true;
            int pos = 0;
            while (pos < _pattern.size())
            {
                if (pos < _pattern.size() && _pattern[pos] != '%') // 目前_pattern的字符只是普通字符的情况
                {
                    string_value.append(1, _pattern[pos]);
                    pos++;
                    continue;
                }
                if (pos + 1 < _pattern.size() && _pattern[pos + 1] == '%') // 目前_pattern的字符是%的情况
                {
                    string_value.append(1, '%');
                    pos += 2;
                    continue;
                }
                if (string_value.empty() == false) // 如果当前的string_value不是空的
                {
                    arry.push_back(std::make_tuple(string_value, "", 0));
                    string_value.clear();
                }
                pos++;
                // 到了当前字符是%的的下一个字符的情况
                if (pos < _pattern.size() && isalpha(_pattern[pos]))
                {
                    format_key = _pattern[pos];
                    pos++;
                }
                else
                {
                    cerr << "你这格式不对啊，%后面不是字母" << endl;
                    return false;
                }
                if (pos < _pattern.size() && _pattern[pos] == '{') // 判断子格式%d{%Y-%m-%d}的情况
                {
                    pos++;
                    while (pos < _pattern.size())
                    {
                        if (_pattern[pos] == '}')
                        {
                            sub_false = false;
                            pos++;
                            break;
                        }
                        format_value.append(1, _pattern[pos++]);
                    }
                }
                arry.push_back(std::make_tuple(format_key, format_value, 1));
                format_key.clear();
                format_value.clear();
            }
            if (sub_false)
            {
                cerr << "{}对应出错！" << endl;
                return false;
            }
            if (string_value.empty() == false)
            {
                arry.push_back(std::make_tuple(string_value, "", 0));
            }
            if (format_key.empty() == false)
            {
                arry.push_back(std::make_tuple(format_key, format_value, 1));
            }
            for (auto &it : arry)
            {
                if (std::get<2>(it) == 0)
                {
                    FormatItem::ptr fi(new OtherFormatItem(std::get<0>(it)));
                    _items.push_back(fi);
                }
                else if (std::get<2>(it) == 1)
                {
                    FormatItem::ptr fi = createItem(std::get<0>(it), std::get<1>(it));
                    if (fi.get() == nullptr)
                    {
                        cerr << "没有对应的格式化字符：%" << std::get<0>(it) << endl;
                        return false;
                    }
                    _items.push_back(fi);
                }
            }
            return true;
        }

    private:
        FormatItem::ptr createItem(const string &key, const string &value)
        {
            if (key == "m")
                return std::make_shared<MsgFormatItem>();
            if (key == "p")
                return std::make_shared<LevelFormatItem>();
            if (key == "c")
                return std::make_shared<NameFormatItem>();
            if (key == "t")
                return std::make_shared<TidFormatItem>();
            if (key == "n")
                return std::make_shared<NlineFormatItem>();
            if (key == "d")
                return std::make_shared<TimeFormatItem>(value);
            if (key == "f")
                return std::make_shared<FileFormatItem>();
            if (key == "l")
                return std::make_shared<LineFormatItem>();
            if (key == "T")
                return std::make_shared<TabFormatItem>();
            return nullptr;
        }

    private:
        string _pattern; // 格式化规则字符串
        std::vector<FormatItem::ptr> _items;
    };
};